package com.aisile.crowd_funding.common.aspect;

import com.aisile.crowd_funding.common.annotion.Log;
import com.aisile.crowd_funding.common.utils.ShiroUtils;
import com.aisile.crowd_funding.system.pojo.SysLog;
import com.aisile.crowd_funding.system.pojo.SysUser;
import com.aisile.crowd_funding.system.service.LogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 日志切面类
 * @标题 LogAspect
 * @作者 Mr.chen
 * @创建日期 2018/12/13 10:48
 * @版本号 1.0
 **/
@Aspect //注解  当前类  变为切面类
@Component
public class LogAspect {

    @Autowired
    LogService logService;

    /**
     * 所有  用 @Log 注解  标注的方法  归 这个 切面类处理
     */
    @Pointcut("@annotation(com.aisile.crowd_funding.common.annotion.Log)")
    public void Pointcut(){
    }

    /**
     * 环绕通知
     * @param point
     */
    @Around("Pointcut()")
    public Object Around(ProceedingJoinPoint point) throws Throwable{
        Object proceed = null;
        try {
            // 前置通知
            long startTime = System.currentTimeMillis();
            proceed  = point.proceed();//执行目标方法
            // 后置通知
            long endTime = System.currentTimeMillis();
            SysLog sysLog = new SysLog();
            sysLog.setGmtCreate(new Date());
            //方法持续时间:
            System.out.println("方法执行时间:"+(endTime-startTime));
            sysLog.setTime((int)(endTime-startTime));
            //Shiro
            SysUser sysUser = ShiroUtils.getUser();
            System.out.println("当前操作用户:"+sysUser.getUsername());
            sysLog.setUserId(sysUser.getUserId());
            sysLog.setUsername(sysUser.getUsername());
            // 利用反射 获取 Log注解当中的值
            MethodSignature methodSignature = (MethodSignature)point.getSignature();
            Method method = methodSignature.getMethod();
            //利用反射 获取方法上的 注解
            Log log = method.getAnnotation(Log.class);
            String operation = log.value();//得到操作
            System.out.println("当前操作:"+operation);
            sysLog.setOperation(operation);
            System.out.println("方法名称:"+ method.getName());
            sysLog.setMethod(method.getName());
            System.out.println("方法所在类:"+method.getDeclaringClass().toString());
            //  IP需要  request 对象来获取
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            System.out.println("本地IP:"+ request.getLocalAddr());
            System.out.println("远程IP:"+ request.getRemoteAddr());
            sysLog.setIp(request.getRemoteAddr());
            //插入到日志表
            logService.insert(sysLog);

        }catch (Exception e){
            // 异常通知
        }finally {
            // 最终通知
        }
        return proceed;
    }
}
